from django.views.generic import TemplateView
from pyecharts import options as opts
from pyecharts.charts import Radar, Bar, Line, Scatter, Pie
from pyecharts.globals import ThemeType
from accounts.models import StudentSurvey


class InterestAnalysisView(TemplateView):
    template_name = 'charts/interest_analysis.html'

    def __init__(self):
        self.model = StudentSurvey

     # 统计各个活动项目参与过的人次分布，使用柱状图，柱状图有两条柱子，按照性别进行区分，在加上图例，返回一个 pyecharts 对象
    def get_activity_type_distribution(self):
        # 从数据库获取所有调查数据
        surveys = self.model.objects.all()

        # 按性别分组的调查数据
        male_surveys = surveys.filter(gender='M')
        female_surveys = surveys.filter(gender='F')

        # 定义所有活动项目字段
        # , 'sports', 'dance', 'band','marching', 'music', 'rock'
        activity_fields = [
            'basketball', 'football', 'soccer', 'softball', 'volleyball',
            'swimming', 'baseball', 'tennis'
        ]

        # 添加对应的中文名称
        # '体育运动', '舞蹈', '乐队', '军乐队', '音乐', '摇滚音乐'
        activity_names = [
            '篮球', '足球', '英式足球', '垒球', '排球',
            '游泳', '棒球', '网球',
        ]

        # 统计每个活动项目的参与人次（兴趣度>0表示参与）
        male_counts = []
        female_counts = []

        for i, field in enumerate(activity_fields):
            # 计算男性参与人次
            male_participants = 0
            for survey in male_surveys:
                if getattr(survey, field, 0) > 0:
                    male_participants += 1
            male_counts.append(male_participants)

            # 计算女性参与人次
            male_participants = 0
            for survey in female_surveys:
                if getattr(survey, field, 0) > 0:
                    male_participants += 1
            female_counts.append(male_participants)

        # 创建柱状图
        activity_bar = (
            Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='500px'))
            .add_xaxis(activity_names)
            .add_yaxis(
                "女生参与人次",
                female_counts,
                category_gap="50%",
                gap="0%",
                stack="stack1",
                itemstyle_opts=opts.ItemStyleOpts(
                    color="#91cc75",
                    border_radius=[0, 0, 0, 0]
                )
            )
            .add_yaxis(
                "男生参与人次",
                male_counts,
                category_gap="50%",
                gap="0%",
                stack="stack1",
                itemstyle_opts=opts.ItemStyleOpts(
                    color="#5470c6",
                    border_radius=[7, 7, 0, 0]
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="各体育项目性别参与人次分布"),
                xaxis_opts=opts.AxisOpts(name="体育项目", axislabel_opts=opts.LabelOpts(rotate=30)),
                yaxis_opts=opts.AxisOpts(name="参与人次"),
                legend_opts=opts.LegendOpts(pos_top="5%"),
                tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow")
            )
            .set_series_opts(
                label_opts=opts.LabelOpts(is_show=True, position="inside")
            )
        )

        return activity_bar.render_embed()

    # 统计各个体育运动和年龄之间关系的散点图

    def get_activity_age_scatter(self):
        surveys = self.model.objects.all()

        # 定义年龄范围的边界点
        age_boundaries = [18, 20, 25, 30, 35, 40, 45, 50, 55, 60, 100]
        age_ranges = ['18-20', '21-25', '26-30', '31-35', '36-40', '41-45', '46-50', '51-55', '56-60', '61+']

        # 定义所有活动项目字段
        activity_fields = [
            'basketball', 'football', 'soccer', 'softball', 'volleyball',
            'swimming', 'baseball', 'tennis'
        ]

        activity_names = [
            '篮球', '足球', '英式足球', '垒球', '排球',
            '游泳', '棒球', '网球',
        ]

        # 按年龄段和活动类型统计参与人次
        activity_data = []

        # 按年龄段分类调查数据，为每个活动创建一个系列
        for field_idx, field in enumerate(activity_fields):
            series_data = []

            for i in range(len(age_ranges)):
                # 定义年龄范围
                min_age = age_boundaries[i]
                max_age = age_boundaries[i+1] - 1 if i < len(age_boundaries) - 2 else 999

                # 统计该年龄段内对特定活动有兴趣的人数
                count = surveys.filter(
                    age__gte=min_age,
                    age__lte=max_age
                ).filter(**{f"{field}__gt": 0}).count()

                series_data.append(count)

            activity_data.append((activity_names[field_idx], series_data))

        # 创建折线图，更适合展示多个活动的年龄分布
        line = (
            Line(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='100%'))
            .add_xaxis(age_ranges)
        )

        # 添加每个活动的数据系列
        for name, data in activity_data:
            line.add_yaxis(
                name,
                data,
                symbol_size=8,
                is_symbol_show=True,
                label_opts=opts.LabelOpts(is_show=False),
                linestyle_opts=opts.LineStyleOpts(width=2)
            )

        # 设置全局选项
        line.set_global_opts(
            title_opts=opts.TitleOpts(title="各体育运动在不同年龄段的参与情况"),
            xaxis_opts=opts.AxisOpts(
                name="年龄段",
                type_="category",
                axislabel_opts=opts.LabelOpts(rotate=30)
            ),
            yaxis_opts=opts.AxisOpts(name="参与人数"),
            legend_opts=opts.LegendOpts(pos_top="5%", orient="vertical", pos_right="5%"),
            tooltip_opts=opts.TooltipOpts(trigger="axis")
        )

        return line.render_embed()

    # 添加饼图展示不同类型运动的占比
    def get_sports_preference_pie(self):
        # 从数据库获取所有调查数据
        surveys = self.model.objects.all()

        # 定义所有活动项目字段
        activity_fields = [
            'basketball', 'football', 'soccer', 'softball', 'volleyball',
            'swimming', 'baseball', 'tennis'
        ]

        # 添加对应的中文名称
        activity_names = [
            '篮球', '足球', '英式足球', '垒球', '排球',
            '游泳', '棒球', '网球',
        ]

        # 统计每个活动的总兴趣度（将所有用户对该活动的兴趣度求和）
        activity_interest = []
        for i, field in enumerate(activity_fields):
            # 计算总兴趣度
            total_interest = 0
            interested_count = 0

            for survey in surveys:
                interest_level = getattr(survey, field, 0)
                if interest_level > 0:
                    total_interest += interest_level
                    interested_count += 1

            # 计算平均兴趣度
            avg_interest = 0
            if interested_count > 0:
                avg_interest = round(total_interest / interested_count, 2)

            activity_interest.append((activity_names[i], interested_count, avg_interest))

        # 按参与人数排序
        activity_interest.sort(key=lambda x: x[1], reverse=True)

        # 提取饼图所需的数据
        pie_data = [(item[0], item[1]) for item in activity_interest]

        # 创建饼图
        pie = (
            Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='500px'))
            .add(
                series_name="运动偏好",
                data_pair=pie_data,
                radius=["40%", "70%"],
                center=["50%", "50%"],
                label_opts=opts.LabelOpts(
                    formatter="{b}: {c} ({d}%)",
                    font_size=14
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(
                    title="不同运动项目偏好分布",
                    subtitle="基于参与人数统计"
                ),
                legend_opts=opts.LegendOpts(
                    orient="vertical",
                    pos_left="85%",
                    pos_top="middle"
                ),
                tooltip_opts=opts.TooltipOpts(
                    trigger="item",
                    formatter="{a} <br/>{b}: {c} 人 ({d}%)"
                )
            )
        )

        return pie.render_embed()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context['navname'] = 'interests'
        context['activity_chart'] = self.get_activity_type_distribution()
        context['scatter_chart'] = self.get_activity_age_scatter()
        context['pie_chart'] = self.get_sports_preference_pie()
        return context
